/**
  ******************************************************************************
  * @file    bsp nand.h
  * @author  Iron
  * @date    2018-07-09
  * @version v1.0
  * @brief   bsp nand header file
  */

#ifndef __BSP_NAND_H
#define __BSP_NAND_H

#ifdef __cplusplus
extern "C" {
#endif

/* includes ------------------------------------------------------------------*/
#include <stdint.h>
#include "bsp.h"

/* exported types ------------------------------------------------------------*/
/* exported constants --------------------------------------------------------*/
/* exported macro ------------------------------------------------------------*/
#define BSP_NAND_FAIL                    0
#define BSP_NAND_OK                      1
#define BSP_NAND_ECC_OK                  2
#define BSP_NAND_ECC_ERROR               3

/* nandflash confg */
#define BSP_NAND_TOTAL_BLOCKS            1024
#define BSP_NAND_PAGE_DATA_SIZE          2048
#define BSP_NAND_PAGE_SPARE_SIZE         64
#define BSP_NAND_PAGES_PER_BLOCK         64
#define BSP_NAND_ECC_SIZE                4

/* PORT CONFIG ---------------------------------------------------------------*/
#define nand_delay_us(us)          bsp_us_delay(us)
#define nand_get_rb()              HAL_GPIO_ReadPin(GPIOD, GPIO_PIN_6)

#define NAND_RB_RESET              GPIO_PIN_RESET
#define NAND_RB_SET                GPIO_PIN_SET

#define NAND_ADDRESS               NAND_DEVICE1 // NAND_BANK2
#define _CMD_AREA                  ((uint32_t)(1U<<17U))  /* A16 = ALE high */
#define _ADDR_AREA                 ((uint32_t)(1U<<16U))  /* A17 = CLE high */

#define NAND_CMD(cmd)              *(__IO uint8_t *)((uint32_t)(NAND_ADDRESS | _CMD_AREA)) = (cmd)
#define NAND_ADDR(addr)            *(__IO uint8_t *)((uint32_t)(NAND_ADDRESS | _ADDR_AREA)) = (addr)

#define NAND_DATA_READ_WORD()      *(__IO uint32_t *)NAND_ADDRESS   // used for read ID
#define NAND_DATA_READ_BYTE()      *(__IO uint8_t  *)NAND_ADDRESS
#define NAND_DATA_WRITE_BYTE(data) *(__IO uint8_t  *)NAND_ADDRESS = (data)

#define NAND_ECC_ENABLE()          FMC_NAND_ECC_Enable(FSMC_NAND_DEVICE, FSMC_NAND_BANK2)
#define NAND_ECC_DISABLE()         FMC_NAND_ECC_Disable(FSMC_NAND_DEVICE, FSMC_NAND_BANK2)
#define NAND_ECC_GET_VALUE(val)    FMC_NAND_GetECC(FSMC_NAND_DEVICE, val, FSMC_NAND_BANK2, 10)

/* RTOS & DMA SURPPORT -------------------------------------------------------*/
#define NAND_RTOS_ENABLE
#define NAND_DMA_ENABLE     // need RTOS mutex support, almost 20% efficiency improvement.

#ifdef NAND_RTOS_ENABLE

#include "FreeRTOS.h"
#include "semphr.h"

#define BSP_NAND_RTOS_MUTEX_TIMEOUT    portMAX_DELAY

extern SemaphoreHandle_t nand_mutex_handle;
extern StaticSemaphore_t nand_mutex;

#define BSP_NAND_RTOS_MUTEX_INIT() \
  do{nand_mutex_handle = xSemaphoreCreateMutexStatic(&nand_mutex);}while(0)

#define BSP_NAND_RTOS_MUTEX_WAIT() \
  do{  \
    if( xSemaphoreTake(nand_mutex_handle, pdMS_TO_TICKS(BSP_NAND_RTOS_MUTEX_TIMEOUT)) != pdPASS) {  \
      DBG_LOGE(TAG, "nand flash mutex wait error or timeout.");  \
      return BSP_NAND_FAIL;  \
    }  \
  }while(0)

#define BSP_NAND_RTOS_MUTEX_RELEASE() \
  do{xSemaphoreGive(nand_mutex_handle);}while(0)

/* NAND DMA sem */
#ifdef NAND_DMA_ENABLE

#define BSP_NAND_DMA_RTOS_SEM_TIMEOUT        500
#define BSP_NAND_DMA_PRE_PRI                 8    /* < 5 && > 15*/
#define BSP_NAND_DMA_SUB_PRI                 0

/* RTOS ISR CIRCEL */
#define BSP_NAND_ENTER_ISR() \
  UBaseType_t uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR()

#define BSP_NAND_EXIT_ISR() \
  portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterruptStatus)

extern SemaphoreHandle_t nand_dma_sem_handle;
extern StaticSemaphore_t nand_dma_sem;

#define BSP_NAND_DMA_RTOS_SEM_INIT() \
  do{nand_dma_sem_handle = xSemaphoreCreateBinaryStatic(&nand_dma_sem);}while(0)

#define BSP_NAND_DMA_RTOS_SEM_CLEAR() \
  do{while(xSemaphoreTake(nand_dma_sem_handle, 0) == pdPASS){}}while(0)

#define BSP_NAND_DMA_RTOS_SEM_WAIT() \
  do{  \
    if( xSemaphoreTake(nand_dma_sem_handle, pdMS_TO_TICKS(BSP_NAND_DMA_RTOS_SEM_TIMEOUT)) != pdPASS) {  \
      DBG_LOGE(TAG, "nand flash dma sem wait timeout");  \
      return BSP_NAND_FAIL;  \
    }  \
   }while(0)

#define BSP_NAND_DMA_ISR_RTOS_SEM_RELEASE() \
  do{  \
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;  \
    xSemaphoreGiveFromISR(nand_dma_sem_handle, &xHigherPriorityTaskWoken);  \
    portYIELD_FROM_ISR( xHigherPriorityTaskWoken );  \
  }while(0)

int32_t bsp_nand_dma_write(const uint8_t *dst, size_t size);
int32_t bsp_nand_dma_read(uint8_t *dst, size_t size);

#else
#define BSP_NAND_DMA_RTOS_SEM_INIT()
#endif

#else

#define BSP_NAND_RTOS_MUTEX_INIT()
#define BSP_NAND_RTOS_MUTEX_WAIT()
#define BSP_NAND_RTOS_MUTEX_RELEASE()

#if defined NAND_DMA_ENABLE && !defined NAND_RTOS_ENABLE
#error Nand flash dma mode driver need RTOS support!
#endif

#define BSP_NAND_DMA_RTOS_SEM_INIT()

#endif // NAND_RTOS_ENABLE

/* exported functions ------------------------------------------------------- */
int32_t bsp_nand_data_correct(uint32_t generatedEcc, uint32_t readEcc, uint8_t *data);
int32_t bsp_nand_wait_rb(uint32_t st, uint32_t timeout_us);
uint32_t bsp_nand_read_status(void);
int32_t bsp_nand_reset(void);

//int32_t bsp_nand_flash_read_page( const bsp_nand_handle_t *hnand, uint32_t page,
//                                  uint8_t* data, uint32_t data_len,
//                                  uint8_t *spare, uint32_t spare_len);

//int32_t bsp_nand_flash_write_page( const bsp_nand_handle_t *hnand, uint32_t page,
//                                   const uint8_t * data, uint32_t data_len,
//                                   const uint8_t * spare, uint32_t spare_len);

//int32_t bsp_nand_flash_move_page(const bsp_nand_handle_t *hnand, uint32_t src_page, uint32_t dst_page);

//int32_t bsp_nand_flash_erase_block(const bsp_nand_handle_t *hnand, uint32_t block);

//int32_t bsp_nand_flash_check_block(const bsp_nand_handle_t *hnand, uint32_t block);

//int32_t bsp_nand_flash_mark_badblock(const bsp_nand_handle_t *hnand, uint32_t block);

int32_t bsp_nand_flash_init(void);

/**
  * @}
  */

#ifdef __cplusplus
}
#endif

#endif /* __BSP_NAND_H */

/******************* (C)COPYRIGHT 2018 ***** END OF FILE *********************/
